import React, {Component} from 'react';
import hoistNonReactStatic from 'hoist-non-react-statics';

/**
 * @module ajax高阶组件，解决组件销毁，同时销毁请求的问题
 @example
 * 初始化
 fetch.init({
    baseURL: BASE_URL,
    timeout: 200000,
    onShowSuccessTip: (response, successTip) => {
        if(successTip) Toast.info(successTip, 2);
    },
    isMock: (url) => {
        return url.startsWith('/mock');
    }
  });

 * 统一请求拦截处理
 export const requestInterceptors = dispatch => {
    const { DeviceId = '', UserAgent = '' } = GlobalValues;

    fetch.axiosInstance.defaults.headers['APP-Agent'] = `Xlm-app|${VERSION_CODE}|${OS_MAP[Platform.OS]}`;
    fetch.axiosInstance.defaults.headers['Token-IMEI'] = DeviceId;
    fetch.axiosInstance.defaults.headers['User-Agent'] = UserAgent;

    fetch.axiosInstance.interceptors.request.use(cfg => {

        if(userInfo) {
          const time = getTimestamp();
          const url = cfg.url.replace(cfg.baseURL, '');

          cfg.headers.common['Token-timestamp'] = time;
          cfg.headers.common['Token-userId'] = userInfo.userId;
          const tokenParam = [
            `userId=${userInfo.userId}`,
            `timestamp=${time}`,
            `token=${userInfo.token}`,
            `imei=${DeviceId}`,
          ].join('&');

          cfg.headers.common['Token-param'] = md5(`${url.split('?')[0]}?${tokenParam}`);
          } else {
            cfg.headers.common['registerToken'] = DeviceId;
          }

          return cfg;
          }, error => {
            return Promise.reject(error);
          });
        }

 * 统一服务端响应拦截拦截处理
 export const responseInterceptors = dispatch => {
        fetch.axiosInstance.interceptors.response.use(res => {
            return res;
        }, error => {
            const { response = {}, config = {} } = error;
            const { errorTip = '' } = config;

            if (errorTip) {
                Toast.fail(errorTip, 2);
            } else if (error.toString().indexOf('timeout') > -1) {
                Toast.fail('请求超时！', 2);
            } else if(response.status === 401) {
                Toast.info('请重新登录');
                logOut();
                setTimeout(() => {
                    dispatch(resetAction('Login'));
                }, 100);
            } else if (response.status === 403) {
                versionModal(true);
            } else if (response.data && response.data.message) {
                Toast.fail(response.data.message, 2);
            } else {
                Toast.fail('请求失败', 2);
            }

            return Promise.reject(error);
        });
    }

 * 使用
 import fetch from 'sx-fetch/src';
 @fetch.inject()
 export default class HomePage extends Component {
  componentDidMount(){
    this.props.$fetch.get(`event/v1/cardProfitFeedBack/feedBackDetails/${uuid}`)
      .then(res => {
        ...
      }.catch(e){
        ...
      }
  }
 }

 */

function fetchInject({propName = '$fetch'} = {}) {
  const that = this;
  return function (WrappedComponent) {
    class WithSubscription extends Component {
      constructor(props) {
        super(props);
        this[propName] = {};
        this._$fetchTokens = [];
        const fetchMethods = ['get', 'post', 'put', 'patch', 'del', 'singleGet', 'all'];

        for (let method of fetchMethods) {
          this[propName][method] = (...args) => {
            const fetchToken = that[method](...args);
            this._$fetchTokens.push(fetchToken);
            return fetchToken;
          };
        }
      }

      static displayName = `WithSubscription(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;

      componentWillUnmount() {
        const _$fetchTokens = this._$fetchTokens;
        _$fetchTokens.forEach(item => item.cancel());
      }

      render() {
        const fetchProp = this[propName];
        const injectProps = {
          [propName]: fetchProp,
        };
        return <WrappedComponent {...injectProps} {...this.props}/>;
      }
    }

    /* 讲原组件的所有非react属性绑定新组件中 */
    hoistNonReactStatic(WithSubscription, WrappedComponent);

    return WithSubscription;
  };
}

export default fetchInject;
